#include "wtlpch.h"

#include "LiteXMLPhaser.h"

CLiteXMLPhaser::CLiteXMLPhaser(LPCWSTR lpwszRelativeFilePath, OPMODE opMode) : m_wstrXMLFileName(L""), m_pReader(NULL), m_pIStream(NULL)
{
	//Set Operation Mode
	m_opMode = opMode;

	//Init the XML Lite
	if(m_opMode == READ_MODE)		//Read XML Mode
	{
		if(FAILED(CreateXmlReader(__uuidof(IXmlReader), reinterpret_cast<void**>(&m_pReader), NULL)))
		{
			setStatus(ST_ERROR_INIT);
			return;
		}
	}
	else						//Write XML Mode
	{
		if(FAILED(CreateXmlWriter(__uuidof(IXmlWriter), reinterpret_cast<void**>(&m_pWriter), NULL)))
		{
			setStatus(ST_ERROR_INIT);
			return;
		}		
	}
	
	//Create IStream from a file
	if(resetIStream(lpwszRelativeFilePath) == S_OK)
	{
		setStatus(ST_OK);
	}
}


CLiteXMLPhaser::~CLiteXMLPhaser()
{
	//Release Stream Resources
	if(m_pIStream != NULL)
	{
		m_pIStream->Release();
	}

	//Release XML Lite Resource
	if(m_opMode == READ_MODE)
	{
		m_pReader != NULL ? m_pReader->Release() : NULL;
	}
	else
	{
		m_pWriter != NULL ? m_pWriter->Release() : NULL;
	}
}

HRESULT CLiteXMLPhaser::getNextCDATA(LPCWSTR lpwszElementPath, LPCWSTR lpwszPropPath, LPWSTR lpwszCDATA, bool bSubCall)
{
	return getNextTemplate<XmlNodeType_CDATA>(lpwszElementPath, lpwszPropPath, lpwszCDATA, bSubCall);
}

HRESULT CLiteXMLPhaser::getNextText(LPCWSTR lpwszElementPath, LPCWSTR lpwszPropPath, LPWSTR lpwszCDATA, bool bSubCall)
{
	return getNextTemplate<XmlNodeType_Text>(lpwszElementPath, lpwszPropPath, lpwszCDATA, bSubCall);
}


HRESULT CLiteXMLPhaser::resetIStream(LPCWSTR lpwszRelativeFilePath)
{
	//Ret to the new filename
	if(lpwszRelativeFilePath != NULL || m_wstrXMLFileName.size() == 0)
	{
		//Make the XML filepath
		WCHAR lpwszXML[MAX_PATH];
		::GetModuleFileName(NULL, lpwszXML, MAX_PATH);
		::PathRemoveFileSpec(lpwszXML);
		::PathAppend(lpwszXML, lpwszRelativeFilePath);
		m_wstrXMLFileName = lpwszXML;
	}

	//Release the exist IStream
	if(m_pIStream != NULL)
	{
		m_pIStream->Release();
	}

	m_pIStream = NULL;

	//Create IStream from a file
	if(m_opMode == READ_MODE)
	{
		if(FAILED(SHCreateStreamOnFile(m_wstrXMLFileName.c_str(), STGM_READ | STGM_SHARE_DENY_NONE, &m_pIStream)))
		{
			//This is for the Constructor
			setStatus(ST_ERROR_FILE);
			return S_FALSE;
		}

		//No need to AddRef, just for a [in] Param according COM rule
		if(FAILED(m_pReader->SetInput(m_pIStream)))
		{
			m_pReader->Release();
			m_pIStream->Release();
			m_pReader = NULL;
			m_pIStream = NULL;

			setStatus(ST_ERROR_XMLPHASE);
			return S_FALSE;
		}	
	}
	else
	{
		if(FAILED(SHCreateStreamOnFile(m_wstrXMLFileName.c_str(), STGM_WRITE | STGM_SHARE_DENY_WRITE | STGM_CREATE, &m_pIStream)))
		{
			setStatus(ST_ERROR_FILE);
			return S_FALSE;
		}

		if(FAILED(m_pWriter->SetOutput(m_pIStream)))
		{
			m_pWriter->Release();
			m_pIStream->Release();
			m_pWriter = NULL;
			m_pIStream = NULL;

			setStatus(ST_ERROR_XMLPHASE);
			return S_FALSE;
		}		
	}

	return S_OK;
}


HRESULT CLiteXMLPhaser::writeElementList(CLiteXMLPhaser::XMLElements* pElements)
{
	ATLASSERT(m_pWriter != NULL && pElements != NULL);

	UINT unElementsSize = pElements->vecpwstrEleContents.size();

	//Write the elements
	for(UINT i = 0; i < unElementsSize; i++)
	{
		m_pWriter->WriteStartElement(NULL, pElements->wstrEleName.c_str(), NULL);

		//If there is attributs, write them
		if(pElements->vecvpwstrEleAttr[i] != NULL)
		{
			for(UINT j = 0; j < pElements->vecvpwstrEleAttr[i]->size(); j++)
			{
				m_pWriter->WriteAttributeString(NULL, (*pElements->vecvpwstrEleAttr[i])[j].c_str(), NULL, (*pElements->vecvpwstrEleAttrValue[i])[j].c_str());
			}
		}

		if(pElements->bCDATA)
		{
			m_pWriter->WriteCData(pElements->vecpwstrEleContents[i]->c_str());
		}
		else
		{
			m_pWriter->WriteString(pElements->vecpwstrEleContents[i]->c_str());
		}

		//Close current element tag
		m_pWriter->WriteFullEndElement();
	}

	return S_OK;
}


HRESULT CLiteXMLPhaser::writePartList(CLiteXMLPhaser::XMLPart* pXMLParts)
{
	ATLASSERT(m_pWriter != NULL && pXMLParts != NULL);

	//Write the element name
	m_pWriter->WriteStartElement(NULL, pXMLParts->wstrPartEleName.c_str(), NULL);

	//Write the son or self elements
	if(pXMLParts->bIsSon)
	{
		writePartList((XMLPart*)(pXMLParts->pSonOrList));
	}
	else
	{
		writeElementList((XMLElements*)(pXMLParts->pSonOrList));
	}

	//Write this End tag
	m_pWriter->WriteFullEndElement();

	//If has siblings, write that
	if(pXMLParts->pxmlPartSibling != NULL)
	{
		writePartList(pXMLParts->pxmlPartSibling);
	}

	return S_OK;
}

HRESULT CLiteXMLPhaser::writeXMLFile(CLiteXMLPhaser::XMLFile* pxmlFile)
{
	ATLASSERT(m_pWriter != NULL && pxmlFile != NULL);
	
	//Set Document Property and write header
	m_pWriter->SetProperty(XmlWriterProperty_Indent, TRUE);
	m_pWriter->WriteStartDocument(XmlStandalone_Omit);

	writePartList(pxmlFile->pxmlRoot);
	
	//End the document and flush to disk
	m_pWriter->WriteEndDocument();
	m_pWriter->Flush();

	return S_OK;
}